home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / misc / moonbas2 / vga.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  18.1 KB  |  782 lines

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <conio.h>
  4. #include <dos.h>
  5.  
  6. #include "boolean.h"
  7. #include "vga.h"
  8.  
  9. char * const       screen_lin_addr = (char *) 0xA0000;
  10.  
  11. const              video_int       = 0x10;
  12.  
  13. const              screen_width    = 320;
  14. const              screen_height   = 200;
  15. const              bytes_per_row   = 320;
  16.  
  17. //----------------------------------------------------------------------------
  18. // The VGA object.  (Only one is allowed.)
  19. //----------------------------------------------------------------------------
  20.  
  21. vga_t              vga;
  22.  
  23. //----------------------------------------------------------------------------
  24. // The offscreen drawing buffer.
  25. //----------------------------------------------------------------------------
  26.  
  27. static char        vga_buf [ 64000 ];
  28.  
  29. //----------------------------------------------------------------------------
  30. // FUNCTION  swap
  31. //----------------------------------------------------------------------------
  32.  
  33. inline void        swap
  34. (
  35.    int&            var1,
  36.    int&            var2
  37. )
  38. {
  39.    int             temp;
  40.  
  41.    temp  =  var1;
  42.    var1  =  var2;
  43.    var2  =  temp;
  44. }
  45.  
  46. //----------------------------------------------------------------------------
  47. // FUNCTION  vga_t::exists
  48. //----------------------------------------------------------------------------
  49. // Checks to see if there is a VGA display adapter.  Returns true if there
  50. // is, false if there isn't.
  51. //----------------------------------------------------------------------------
  52.  
  53. boolean            vga_t::exists
  54. (
  55.    void
  56. )
  57. {
  58.    boolean         exists;
  59.    union REGS      regs;
  60.  
  61.    regs.h.ah = 0x1A;
  62.    regs.h.al = 0;
  63.  
  64.    int386 ( video_int, & regs, & regs );
  65.  
  66.    if ( regs.h.al == 0x1A )
  67.       exists  =  true;
  68.    else
  69.       exists  =  false;
  70.  
  71.    return  exists;
  72. }
  73.  
  74. //----------------------------------------------------------------------------
  75. // FUNCTION  vga_t::start
  76. //----------------------------------------------------------------------------
  77. // Saves the current video mode and switches to mode 13h.
  78. //----------------------------------------------------------------------------
  79.  
  80. void               vga_t::start
  81. (
  82.    void
  83. )
  84. {
  85.    union REGS      regs;
  86.  
  87.    regs.x.eax = 0x0013;
  88.  
  89.    int386 ( video_int, & regs, & regs );
  90. }
  91.  
  92. //----------------------------------------------------------------------------
  93. // FUNCTION  vga_t::end
  94. //----------------------------------------------------------------------------
  95. // Restores the previous video mode.
  96. //----------------------------------------------------------------------------
  97.  
  98. void               vga_t::end
  99. (
  100.    void
  101. )
  102. {
  103.    union REGS      regs;
  104.  
  105.    regs.x.eax = 0x0003;
  106.  
  107.    int386 ( video_int, & regs, & regs );
  108. }
  109.  
  110. //----------------------------------------------------------------------------
  111. // FUNCTION  vga_t::update
  112. //----------------------------------------------------------------------------
  113. // Copies the drawing buffer into screen memory.
  114. //----------------------------------------------------------------------------
  115.  
  116. void               vga_t::update
  117. (
  118.    void
  119. )
  120. {
  121. //   while ( (inp (0x3da) & 8) != 0 )
  122. //      ;
  123.  
  124. //   while ( (inp (0x3da) & 8) == 0 )
  125. //      ;
  126.  
  127.    memcpy ( screen_lin_addr, vga_buf, 64000 );
  128. }
  129.  
  130. //----------------------------------------------------------------------------
  131. // FUNCTION  vga_t::clear
  132. //----------------------------------------------------------------------------
  133. // Fills the entire screen buffer with the given color.
  134. //----------------------------------------------------------------------------
  135.  
  136. void               vga_t::clear
  137. (
  138.    int             color
  139. )
  140. {
  141.    memset ( vga_buf, color, sizeof (vga_buf) );
  142. }
  143.  
  144. //----------------------------------------------------------------------------
  145. // FUNCTION  win_t::resize
  146. //----------------------------------------------------------------------------
  147. // Resizes the clipping window to the given coordinates.
  148. //----------------------------------------------------------------------------
  149.  
  150. void               win_t::resize
  151. (
  152.    int             new_x1,
  153.    int             new_y1,
  154.    int             new_x2,
  155.    int             new_y2
  156. )
  157. {
  158.    x1 = new_x1;
  159.    y1 = new_y1;
  160.    x2 = new_x2;
  161.    y2 = new_y2;
  162. }
  163.  
  164. //----------------------------------------------------------------------------
  165. // FUNCTION  win_t::clear
  166. //----------------------------------------------------------------------------
  167. // Fills a window with the given color.
  168. //----------------------------------------------------------------------------
  169.  
  170. void               win_t::clear
  171. (
  172.    int             color
  173. )
  174. {
  175.    char *          addr;
  176.    int             width;
  177.    int             height;
  178.  
  179.    addr   = vga_buf + (y1 * bytes_per_row) + x1;
  180.    width  = x2 - x1;
  181.    height = y2 - y1;
  182.  
  183.    while ( height > 0 )
  184.    {
  185.       memset ( addr, color, width );
  186.  
  187.       addr   += bytes_per_row;
  188.       height -= 1;
  189.    }
  190. }
  191.  
  192. //----------------------------------------------------------------------------
  193. // FUNCTION  win_t::point
  194. //----------------------------------------------------------------------------
  195. // Draws a point that is clipped to the given window.
  196. //----------------------------------------------------------------------------
  197.  
  198. void               win_t::point
  199. (
  200.    int             x,
  201.    int             y,
  202.    int             color
  203. )
  204. {
  205.    if ( x >= x1 && x < x2 && y >= y1 && y < y2 )
  206.    {
  207.       vga_buf [ y*bytes_per_row + x ] = (char) color;
  208.    }
  209. }
  210.  
  211. //----------------------------------------------------------------------------
  212. // FUNCTION  win_t::rect
  213. //----------------------------------------------------------------------------
  214. // Draws a filled rectangle that is clipped to the given window.
  215. //----------------------------------------------------------------------------
  216.  
  217. void               win_t::rect
  218. (
  219.    int             rect_x1,
  220.    int             rect_y1,
  221.    int             rect_x2,
  222.    int             rect_y2,
  223.    int             color
  224. )
  225. {
  226.    char *          addr;
  227.    int             width;
  228.    int             height;
  229.  
  230.    if ( rect_x2 < x1 || rect_x1 >= x2 ||
  231.         rect_y2 < y1 || rect_y1 >= y2 )
  232.       goto  exit_func;
  233.  
  234.    if ( rect_x1 < x1 )
  235.       rect_x1 = x1;
  236.  
  237.    if ( rect_x2 > x2 )
  238.       rect_x2 = x2;
  239.  
  240.    if ( rect_y1 < y1 )
  241.       rect_y1 = y1;
  242.  
  243.    if ( rect_y2 > y2 )
  244.       rect_y2 = y2;
  245.  
  246.    addr   = vga_buf + (rect_y1 * bytes_per_row) + rect_x1;
  247.    width  = rect_x2 - rect_x1;
  248.    height = rect_y2 - rect_y1;
  249.  
  250.    if ( width > 0 )
  251.    {
  252.       while ( height > 0 )
  253.       {
  254.          memset ( addr, color, width );
  255.  
  256.          addr   += bytes_per_row;
  257.          height -= 1;
  258.       }
  259.    }
  260.  
  261. exit_func:
  262.  
  263.    return;
  264. }
  265.  
  266. //----------------------------------------------------------------------------
  267. // FUNCTION  win_t::line
  268. //----------------------------------------------------------------------------
  269. // Draws a line that is clipped to the given window.
  270. //----------------------------------------------------------------------------
  271.  
  272. void               win_t::line
  273. (
  274.    int             line_x1,
  275.    int             line_y1,
  276.    int             line_x2,
  277.    int             line_y2,
  278.    int             color
  279. )
  280. {
  281.    int             delta_x;
  282.    int             delta_y;
  283.  
  284.    // Switch the points so that (line_x1,line_y1) is always the top one.
  285.  
  286.    if ( line_y2 < line_y1 )
  287.    {
  288.       swap ( line_x1, line_x2 );
  289.       swap ( line_y1, line_y2 );
  290.    }
  291.  
  292.    // Compute the x and y deltas.
  293.  
  294.    delta_x  =  line_x2 - line_x1;
  295.    delta_y  =  line_y2 - line_y1;
  296.  
  297.    // Clip the line on the left and right edges.
  298.  
  299.    if ( line_x1 < x1 )
  300.    {
  301.       if ( line_x2 < x1 )  goto  exit_func;
  302.  
  303.       line_y1 += ( delta_y * ( x1 - line_x1 ) / delta_x );
  304.       line_x1  = x1;
  305.    }
  306.    else if ( line_x1 >= x2 )
  307.    {
  308.       if ( line_x2 >= x2 )  goto  exit_func;
  309.  
  310.       line_y1 += ( delta_y * ( x2 - line_x1 ) / delta_x );
  311.       line_x1  = x2 - 1;
  312.    }
  313.  
  314.    if ( line_x2 < x1 )
  315.    {
  316.       line_y2 += ( delta_y * ( x1 - line_x2 ) / delta_x );
  317.       line_x2  = x1;
  318.    }
  319.    else if ( line_x2 >= x2 )
  320.    {
  321.       line_y2 += ( delta_y * ( x2 - line_x2 ) / delta_x );
  322.       line_x2  = x2 - 1;
  323.    }
  324.  
  325.    // Don't draw lines that are completely off the screen.
  326.  
  327.    if ( line_y2 < y1 || line_y1 >= y2 )  goto  exit_func;
  328.  
  329.    // Clip the line on the top edge.
  330.  
  331.    if ( line_y1 < y1 )
  332.    {
  333.       line_x1 += ( delta_x * ( y1 - line_y1 ) / delta_y );
  334.       line_y1  = y1;
  335.  
  336.       if ( line_x1 <  x1 )  line_x1 = x1;
  337.       if ( line_x1 >= x2 )  line_x1 = x2 - 1;
  338.    }
  339.  
  340.    // Clip the line on the bottom edge.
  341.  
  342.    if ( line_y2 >= y2 )
  343.    {
  344.       line_x2 += ( delta_x * ( y2 - line_y2 ) / delta_y );
  345.       line_y2  = y2 - 1;
  346.  
  347.       if ( line_x2 <  x1 )  line_x2 = x1;
  348.       if ( line_x2 >= x2 )  line_x2 = x2 - 1;
  349.    }
  350.  
  351.    // Recompute the x and y deltas using the clipped coordinates.
  352.  
  353.    delta_x  =  line_x2 - line_x1;
  354.    delta_y  =  line_y2 - line_y1;
  355.  
  356.    // Draw the line.
  357.  
  358.    {
  359.       char *       pixel_addr;
  360.       int          denominator;
  361.       int          nr_pixels;
  362.       int          frac_x;
  363.       int          frac_y;
  364.       int          add_x;
  365.       const int    add_y = bytes_per_row;
  366.  
  367.  
  368.       if (delta_x > 0)
  369.       {
  370.          add_x   = 1;
  371.       }
  372.       else
  373.       {
  374.          add_x   = -1;
  375.          delta_x = -delta_x;
  376.       }
  377.  
  378.       if ( delta_y > delta_x )
  379.       {
  380.          denominator = delta_y;
  381.          nr_pixels   = delta_y + 1;
  382.       }
  383.       else
  384.       {
  385.          denominator = delta_x;
  386.          nr_pixels   = delta_x + 1;
  387.       }
  388.  
  389.       frac_y = frac_x = denominator >> 1;
  390.  
  391.       pixel_addr = vga_buf + bytes_per_row*line_y1 + line_x1;
  392.  
  393.       for ( ; nr_pixels > 0; -- nr_pixels )
  394.       {
  395.          *pixel_addr = (char) color;
  396.  
  397.          frac_x += delta_x;
  398.  
  399.          if ( frac_x > denominator )
  400.          {
  401.             frac_x     -= denominator;
  402.             pixel_addr += add_x;
  403.          }
  404.  
  405.          frac_y += delta_y;
  406.  
  407.          if ( frac_y > denominator )
  408.          {
  409.             frac_y     -= denominator;
  410.             pixel_addr += add_y;
  411.          }
  412.       }
  413.    }
  414.  
  415. exit_func:
  416.  
  417.    return;
  418. }
  419.  
  420. //----------------------------------------------------------------------------
  421. // FUNCTION  win_t::convex_poly
  422. //----------------------------------------------------------------------------
  423. // Draws a filled polygon that is clipped to the given window.
  424. //
  425. // Limitations: Polygon MUST be convex;
  426. //              Vertex coordinates MUST be given in clockwise order around the
  427. //              polygon.
  428. //----------------------------------------------------------------------------
  429.  
  430. void               win_t::convex_poly
  431. (
  432.    int             nr_points,
  433.    scr_xy_p_t      points,
  434.    int             color
  435. )
  436. {
  437.    int             left_x  [ screen_height ];
  438.    int             right_x [ screen_height ];
  439.  
  440.    int             min_y;
  441.    int             max_y;
  442.  
  443.    int             p1;
  444.    int             p2;
  445.  
  446.    // Load the edges into the left_x and right_x arrays, and find the minimum
  447.    // and maximum Y coordinates of the polygon.
  448.  
  449.    min_y = screen_height;
  450.    max_y = 0;
  451.  
  452.    for ( p1 = 0; p1 < nr_points; ++ p1 )
  453.    {
  454.       int *        edge_x;
  455.       int          px1;
  456.       int          py1;
  457.       int          px2;
  458.       int          py2;
  459.       int          delta_x;
  460.       int          delta_y;
  461.  
  462.  
  463.       p2 = (p1 + 1) % nr_points;
  464.  
  465.       px1 = points [p1].x;
  466.       py1 = points [p1].y;
  467.       px2 = points [p2].x;
  468.       py2 = points [p2].y;
  469.  
  470.       delta_y = py2 - py1;
  471.  
  472.       // Throw out horizontal lines, and choose which side to put the rest on.
  473.  
  474.       if ( delta_y == 0 )
  475.       {
  476.          continue;
  477.       }
  478.       else if ( delta_y > 0 )
  479.       {
  480.          edge_x = right_x;
  481.       }
  482.       else
  483.       {
  484.          edge_x = left_x;
  485.  
  486.          // Swap points so (px1, py1) is the top point.
  487.  
  488.          delta_y = -delta_y;
  489.  
  490.          swap ( px1, px2 );
  491.          swap ( py1, py2 );
  492.       }
  493.  
  494.       delta_x = px2 - px1;
  495.  
  496.       // Ignore edges that are completely off the top or bottom of the screen.
  497.  
  498.       if ( py2 < y1 || py1 >= y2 )  continue;
  499.  
  500.       // Clip the edge with the top of the window.
  501.  
  502.       if ( py1 < y1 )
  503.       {
  504.          px1 += ( delta_x * ( y1 - py1 ) / delta_y );
  505.          py1  = y1;
  506.       }
  507.  
  508.       // Clip the edge with the bottom of the window.
  509.  
  510.       if ( py2 > y2 )
  511.       {
  512.          px2 += ( delta_x * ( y2 - py2 ) / delta_y );
  513.          py2  = y2;
  514.       }
  515.  
  516.       // Adjust the minimum and maximum Y coordinates if necessary.
  517.  
  518.       if ( py1 < min_y )
  519.          min_y = py1;
  520.  
  521.       if ( py2 > max_y )
  522.          max_y = py2;
  523.  
  524.       // Recompute the X and Y deltas using the clipped coordinates.
  525.  
  526.       delta_x  =  px2 - px1;
  527.       delta_y  =  py2 - py1;
  528.  
  529.       // Load the edge into the chosen edge array.
  530.  
  531.       int          x;
  532.       int          y;
  533.       int          x_inc;
  534.       int          x_error;
  535.  
  536.  
  537.       if (delta_x > 0)
  538.       {
  539.          x_inc   = 1;
  540.       }
  541.       else
  542.       {
  543.          x_inc   = -1;
  544.          delta_x = -delta_x;
  545.       }
  546.  
  547.       x       = px1;
  548.       x_error = 0;
  549.  
  550.       // Move the right edge one pixel to the right.
  551.  
  552.       if ( edge_x == right_x )
  553.       {
  554.          ++ x;
  555.       }
  556.  
  557.       for ( y = py1; y < py2; ++ y )
  558.       {
  559.          // Load the edge array with the clipped X coordinate.
  560.  
  561.          if ( x < x1 )
  562.          {
  563.             edge_x [y] = x1;
  564.          }
  565.          else if ( x > x2 )
  566.          {
  567.             edge_x [y] = x2;
  568.          }
  569.          else
  570.          {
  571.             edge_x [y] = x;
  572.          }
  573.  
  574.          x_error += delta_x;
  575.  
  576.          while ( x_error >= delta_y )
  577.          {
  578.             x       += x_inc;
  579.             x_error -= delta_y;
  580.          }
  581.       }
  582.    }
  583.  
  584.    // Now draw the scan line segments.
  585.  
  586.    char *          row_addr;
  587.    char *          addr;
  588.    int             width;
  589.    int             y;
  590.  
  591.    if ( max_y <= min_y )  goto  exit_func;
  592.  
  593.    row_addr = vga_buf + (min_y * bytes_per_row);
  594.  
  595.    for ( y = min_y; y < max_y; ++ y )
  596.    {
  597.       addr  = row_addr + left_x [y];
  598.       width = right_x [y] - left_x [y];
  599.  
  600.       memset ( addr, color, width );
  601.  
  602.       row_addr += bytes_per_row;
  603.    }
  604.  
  605. exit_func:
  606.  
  607.    return;
  608. }
  609.  
  610. //----------------------------------------------------------------------------
  611. // FUNCTION  win_t::v_trapezoid
  612. //----------------------------------------------------------------------------
  613. // Draws a vertical trapezoid that is clipped to the given window.
  614. //----------------------------------------------------------------------------
  615.  
  616. typedef struct
  617. {
  618.    int             y;              // Y coordinate of edge
  619.    int             y_inc;          // Direction of Y advance
  620.    int             y_numerator;    // Numerator of the slope fraction
  621.    int             y_denominator;  // Denominator of the slope fraction
  622.    int             y_error;        // Fractional error accumulator
  623. }
  624. edge_t;
  625.  
  626. typedef edge_t *   edge_p_t;
  627.  
  628. //----------------------------------------------------------------------------
  629.  
  630. inline void        init
  631. (
  632.    edge_t &        edge,
  633.    int             x1,
  634.    int             y1,
  635.    int             x2,
  636.    int             y2
  637. )
  638. {
  639.    edge.y             = y1;
  640.    edge.y_inc         = (y2 > y1) ? 1 : -1;
  641.    edge.y_numerator   = (y2 > y1) ? (y2 - y1) : (y1 - y2);
  642.    edge.y_denominator = x2 - x1;
  643.    edge.y_error       = (edge.y_denominator + 1) / 2;
  644. }
  645.  
  646. //----------------------------------------------------------------------------
  647.  
  648. inline void        update
  649. (
  650.    edge_t &        edge
  651. )
  652. {
  653.    edge.y_error -= edge.y_numerator;
  654.  
  655.    while ( edge.y_error < 0 )
  656.    {
  657.       edge.y       += edge.y_inc;
  658.       edge.y_error += edge.y_denominator;
  659.    }
  660. }
  661.  
  662. //----------------------------------------------------------------------------
  663.  
  664. inline void        draw_col
  665. (
  666.    int             x,
  667.    int             y1,
  668.    int             y2,
  669.    int             win_y1,
  670.    int             win_y2,
  671.    int             color
  672. )
  673. {
  674.    char *          addr;
  675.    int             height;
  676.  
  677.  
  678.    if ( y2 < win_y1 || y1 >= win_y2 )  goto  exit_func;
  679.  
  680.    if ( y1 < win_y1 )
  681.       y1 = win_y1;
  682.  
  683.    if ( y2 > win_y2 )
  684.       y2 = win_y2;
  685.  
  686.  
  687.    addr = vga_buf + bytes_per_row * y1 + x;
  688.  
  689.    for ( height = y2 - y1; height > 0; -- height )
  690.    {
  691.       *addr = (char) color;
  692.  
  693.       addr += bytes_per_row;
  694.    }
  695.  
  696. exit_func:
  697.  
  698.    return;
  699. }
  700.  
  701. //----------------------------------------------------------------------------
  702.  
  703. void               win_t::v_trapezoid
  704. (
  705.    int             l_x,       // Left X
  706.    int             lt_y,      // Left Top Y
  707.    int             lb_y,      // Left Bottom Y
  708.    int             r_x,       // Right X
  709.    int             rt_y,      // Right Top Y
  710.    int             rb_y,      // Right Bottom Y
  711.    int             color
  712. )
  713. {
  714.    int             delta_x;
  715.    int             delta_y_t;
  716.    int             delta_y_b;
  717.    int             x;
  718.    edge_t          top, bot;
  719.  
  720.  
  721.    // The trapezoid will be drawn with vertical lines.
  722.  
  723.    // Compute deltas.  Make l_x < r_x.
  724.  
  725.    delta_x  =  r_x - l_x;
  726.  
  727.    if ( delta_x < 0 )
  728.    {
  729.       swap ( l_x,   r_x   );
  730.       swap ( lt_y, rt_y );
  731.       swap ( lb_y, rb_y );
  732.  
  733.       delta_x = -delta_x;
  734.    }
  735.  
  736.    delta_y_t = rt_y - lb_y;
  737.    delta_y_b = rb_y - lb_y;
  738.  
  739.    // Initialize the top and bottom edge structures.
  740.  
  741.    init ( top, l_x, lt_y, r_x, rt_y );
  742.    init ( bot, l_x, lb_y, r_x, rb_y );
  743.  
  744.    // Throw out trapezoids that are completely off the left or right side of
  745.    // the view window.
  746.  
  747.    if ( r_x < x1 || l_x >= x2 )  goto  exit_func;
  748.  
  749.    // Clip against left edge.
  750.  
  751.    if ( l_x < x1 )
  752.    {
  753.       lt_y += ( delta_y_t * ( x1 - l_x ) / delta_x );
  754.       lb_y += ( delta_y_b * ( x1 - l_x ) / delta_x );
  755.       l_x   = x1;
  756.    }
  757.  
  758.    // Clip against right edge.
  759.  
  760.    if ( r_x >= x2 )
  761.    {
  762.       rt_y += ( delta_y_t * ( x2 - r_x ) / delta_x );
  763.       rb_y += ( delta_y_b * ( x2 - r_x ) / delta_x );
  764.       r_x   = x2;
  765.    }
  766.  
  767.    // Draw the columns.
  768.  
  769.    for ( x = l_x; x < r_x; ++ x )
  770.    {
  771.       draw_col ( x, top.y, bot.y, y1, y2, color );
  772.  
  773.       update ( top );
  774.       update ( bot );
  775.    }
  776.  
  777. exit_func:
  778.  
  779.    return;
  780. }
  781.  
  782.